package com.mangix.api;

import com.mangix.http.MangixHttpHeader;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpResponse;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.BytesContentProvider;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.json.simple.JSONValue;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Created by Ahan on 2014/7/8.
 */
public class MangixClient {

    private HttpClient httpClient;

    public void connect() throws Exception {
        if (httpClient == null) {
            httpClient = new HttpClient();
            try {
                httpClient.start();
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    class MangixObjectInputStream extends InputStream {

        private HttpURLConnection conn;
        private InputStream in;

        public MangixObjectInputStream(HttpURLConnection conn, InputStream in) {
            this.conn = conn;
            this.in = in;
        }

        @Override
        public int read() throws IOException {
            return in.read();
        }

        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            return in.read(b, off, len);
        }

        @Override
        public void close() throws IOException {
            conn.disconnect();
            in.close();
        }
    }

    public InputStream get(String hostname, int port, String key) throws Exception {
        InputStreamResponseListener listener = new InputStreamResponseListener();
        httpClient.newRequest("http://" + hostname + ":" + port + "/objects/" + key)
                .send(listener);
        // Wait for the response headers to arrive
        Response response = listener.get(5, TimeUnit.SECONDS);
        // Look at the response
        if (response.getStatus() == 200)
        {
            return listener.getInputStream();
        } else {
            throw new Exception(response.getReason());
        }
    }

    public void put(String hostname, int port, String key, byte[] value, int replicasNum) throws Exception {
        HttpURLConnection conn = null;
        OutputStream out = null;
        try {
            URL server = new URL("http://" + hostname + ":" + port + "/objects/" + key);
            conn = (HttpURLConnection) server.openConnection();
            conn.setRequestProperty("Connection", "close");
            conn.setRequestProperty(MangixHttpHeader.REPLICAS_NUM, replicasNum + "");
            conn.setRequestMethod("PUT");
            conn.setDoOutput(true);
            out = conn.getOutputStream();
            out.write(value);
            out.close();
            int responseCode = conn.getResponseCode();
            if (responseCode != 200) {
                throw new Exception(conn.getResponseMessage());
            }
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
            if (out != null) {
                out.close();
            }
        }
    }

    public void delete(String hostname, int port, String key) throws Exception {
        Request request = httpClient.newRequest("http://" + hostname + ":" + port + "/objects/" + key)
                .method("DELETE")
                .header("Connection", "close");
        ContentResponse response = request.send();
        if (response.getStatus() != 200 && response.getStatus() != 404) {
            throw new Exception(response.getContentAsString());
        }
    }

    public Map<String, Object>  head(String hostname, int port, String key) throws Exception {
        Request request = httpClient.newRequest("http://" + hostname + ":" + port + "/objects/" + key)
                .method("HEAD")
                .header("Connection", "close");
        ContentResponse response = request.send();
        if (response.getStatus() != 200) {
            System.out.println(response.getStatus());
            throw new Exception(response.getContentAsString());
        }
        String jsonString = response.getHeaders().get(MangixHttpHeader.META);
        Map meta = (Map) JSONValue.parse(jsonString);
        return meta;
    }

    public void close() {
        try {
            if(httpClient != null) {
                httpClient.stop();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
